"""
文件处理模块
提供文件读写、编码检测和批量处理功能
"""

import os
import chardet
import codecs
from pathlib import Path
from typing import List, Dict, Optional, Callable, Any
import json
import xml.etree.ElementTree as ET


class FileHandler:
    """文件处理器"""
    
    def __init__(self):
        self.supported_extensions = {
            '.txt', '.md', '.py', '.js', '.json', '.xml', '.html', '.css', 
            '.sql', '.csv', '.log', '.ini', '.cfg', '.conf'
        }
        self.max_file_size = 100 * 1024 * 1024  # 100MB
    
    def detect_encoding(self, file_path: str) -> Dict[str, Any]:
        """
        检测文件编码
        
        Args:
            file_path: 文件路径
        
        Returns:
            编码信息字典
        """
        try:
            with open(file_path, 'rb') as f:
                raw_data = f.read()
                
            if not raw_data:
                return {'encoding': 'utf-8', 'confidence': 1.0, 'language': None}
            
            # 使用chardet检测编码
            result = chardet.detect(raw_data)
            
            # 如果检测结果置信度较低，尝试常见编码
            if result['confidence'] < 0.7:
                common_encodings = ['utf-8', 'gbk', 'gb2312', 'utf-16', 'ascii']
                for encoding in common_encodings:
                    try:
                        raw_data.decode(encoding)
                        return {'encoding': encoding, 'confidence': 0.8, 'language': None}
                    except UnicodeDecodeError:
                        continue
            
            return result
        except Exception as e:
            return {'encoding': 'utf-8', 'confidence': 0.0, 'error': str(e)}
    
    def read_file(self, file_path: str, encoding: Optional[str] = None) -> str:
        """
        读取文件内容
        
        Args:
            file_path: 文件路径
            encoding: 指定编码，如果为None则自动检测
        
        Returns:
            文件内容
        """
        try:
            if not os.path.exists(file_path):
                raise FileNotFoundError(f"文件不存在: {file_path}")
            
            # 检查文件大小
            file_size = os.path.getsize(file_path)
            if file_size > self.max_file_size:
                raise ValueError(f"文件过大: {file_size} bytes")
            
            if encoding is None:
                encoding_info = self.detect_encoding(file_path)
                encoding = encoding_info['encoding']
            
            # 尝试读取文件
            try:
                with codecs.open(file_path, 'r', encoding=encoding) as f:
                    content = f.read()
                return content
            except UnicodeDecodeError:
                # 如果指定编码失败，尝试自动检测
                encoding_info = self.detect_encoding(file_path)
                encoding = encoding_info['encoding']
                with codecs.open(file_path, 'r', encoding=encoding) as f:
                    content = f.read()
                return content
                
        except Exception as e:
            raise Exception(f"读取文件失败: {str(e)}")
    
    def write_file(self, file_path: str, content: str, encoding: str = 'utf-8') -> bool:
        """
        写入文件内容
        
        Args:
            file_path: 文件路径
            content: 文件内容
            encoding: 编码格式
        
        Returns:
            是否成功
        """
        try:
            # 确保目录存在
            os.makedirs(os.path.dirname(file_path), exist_ok=True)
            
            with codecs.open(file_path, 'w', encoding=encoding) as f:
                f.write(content)
            return True
        except Exception as e:
            raise Exception(f"写入文件失败: {str(e)}")
    
    def convert_encoding(self, file_path: str, target_encoding: str, 
                        backup: bool = True) -> bool:
        """
        转换文件编码
        
        Args:
            file_path: 文件路径
            target_encoding: 目标编码
            backup: 是否备份原文件
        
        Returns:
            是否成功
        """
        try:
            # 检测原文件编码
            encoding_info = self.detect_encoding(file_path)
            source_encoding = encoding_info['encoding']
            
            if source_encoding == target_encoding:
                return True
            
            # 备份原文件
            if backup:
                backup_path = file_path + '.backup'
                import shutil
                shutil.copy2(file_path, backup_path)
            
            # 读取原文件
            content = self.read_file(file_path, source_encoding)
            
            # 写入新编码
            return self.write_file(file_path, content, target_encoding)
            
        except Exception as e:
            raise Exception(f"转换编码失败: {str(e)}")
    
    def batch_process(self, folder_path: str, formatter_func: Callable, 
                     file_pattern: str = "*", recursive: bool = True) -> List[Dict[str, Any]]:
        """
        批量处理文件
        
        Args:
            folder_path: 文件夹路径
            formatter_func: 格式化函数
            file_pattern: 文件匹配模式
            recursive: 是否递归处理子文件夹
        
        Returns:
            处理结果列表
        """
        results = []
        folder = Path(folder_path)
        
        if not folder.exists():
            raise FileNotFoundError(f"文件夹不存在: {folder_path}")
        
        # 获取所有匹配的文件
        if recursive:
            files = list(folder.rglob(file_pattern))
        else:
            files = list(folder.glob(file_pattern))
        
        # 过滤支持的文件类型
        files = [f for f in files if f.is_file() and f.suffix.lower() in self.supported_extensions]
        
        for file_path in files:
            try:
                # 读取文件
                content = self.read_file(str(file_path))
                
                # 应用格式化函数
                formatted_content = formatter_func(content)
                
                # 如果内容有变化，写回文件
                if content != formatted_content:
                    self.write_file(str(file_path), formatted_content)
                    results.append({
                        'file_path': str(file_path),
                        'status': 'modified',
                        'original_size': len(content),
                        'new_size': len(formatted_content)
                    })
                else:
                    results.append({
                        'file_path': str(file_path),
                        'status': 'unchanged',
                        'size': len(content)
                    })
                    
            except Exception as e:
                results.append({
                    'file_path': str(file_path),
                    'status': 'error',
                    'error': str(e)
                })
        
        return results
    
    def get_file_info(self, file_path: str) -> Dict[str, Any]:
        """
        获取文件信息
        
        Args:
            file_path: 文件路径
        
        Returns:
            文件信息字典
        """
        try:
            stat = os.stat(file_path)
            encoding_info = self.detect_encoding(file_path)
            
            return {
                'path': file_path,
                'name': os.path.basename(file_path),
                'size': stat.st_size,
                'modified_time': stat.st_mtime,
                'encoding': encoding_info['encoding'],
                'confidence': encoding_info.get('confidence', 0),
                'extension': Path(file_path).suffix.lower(),
                'is_text_file': Path(file_path).suffix.lower() in self.supported_extensions
            }
        except Exception as e:
            return {
                'path': file_path,
                'error': str(e)
            }
    
    def validate_file(self, file_path: str) -> Dict[str, Any]:
        """
        验证文件
        
        Args:
            file_path: 文件路径
        
        Returns:
            验证结果
        """
        result = {
            'valid': True,
            'errors': [],
            'warnings': []
        }
        
        try:
            if not os.path.exists(file_path):
                result['valid'] = False
                result['errors'].append("文件不存在")
                return result
            
            # 检查文件大小
            file_size = os.path.getsize(file_path)
            if file_size == 0:
                result['warnings'].append("文件为空")
            elif file_size > self.max_file_size:
                result['valid'] = False
                result['errors'].append(f"文件过大: {file_size} bytes")
            
            # 检查文件扩展名
            extension = Path(file_path).suffix.lower()
            if extension not in self.supported_extensions:
                result['warnings'].append(f"不支持的文件类型: {extension}")
            
            # 检查编码
            encoding_info = self.detect_encoding(file_path)
            if encoding_info.get('confidence', 0) < 0.5:
                result['warnings'].append("编码检测置信度较低")
            
            # 尝试读取文件
            try:
                self.read_file(file_path)
            except Exception as e:
                result['valid'] = False
                result['errors'].append(f"无法读取文件: {str(e)}")
                
        except Exception as e:
            result['valid'] = False
            result['errors'].append(f"验证失败: {str(e)}")
        
        return result
    
    def create_backup(self, file_path: str, backup_suffix: str = '.backup') -> str:
        """
        创建文件备份
        
        Args:
            file_path: 文件路径
            backup_suffix: 备份文件后缀
        
        Returns:
            备份文件路径
        """
        import shutil
        backup_path = file_path + backup_suffix
        shutil.copy2(file_path, backup_path)
        return backup_path
    
    def restore_backup(self, file_path: str, backup_suffix: str = '.backup') -> bool:
        """
        从备份恢复文件
        
        Args:
            file_path: 文件路径
            backup_suffix: 备份文件后缀
        
        Returns:
            是否成功
        """
        import shutil
        backup_path = file_path + backup_suffix
        
        if not os.path.exists(backup_path):
            return False
        
        try:
            shutil.copy2(backup_path, file_path)
            return True
        except Exception:
            return False
    
    def get_supported_extensions(self) -> List[str]:
        """获取支持的文件扩展名"""
        return list(self.supported_extensions)
    
    def add_supported_extension(self, extension: str):
        """添加支持的文件扩展名"""
        if not extension.startswith('.'):
            extension = '.' + extension
        self.supported_extensions.add(extension.lower())
    
    def set_max_file_size(self, size_bytes: int):
        """设置最大文件大小限制"""
        self.max_file_size = size_bytes 